package com.liuqi.business.service.impl;


import cn.hutool.core.date.DateUtil;
import com.liuqi.business.enums.WalletLogTypeEnum;
import com.liuqi.business.mapper.*;
import com.liuqi.business.model.*;
import com.liuqi.business.service.MiningGradeRewardService;
import com.liuqi.response.ReturnResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.liuqi.base.BaseMapper;
import com.liuqi.base.BaseServiceImpl;


import com.liuqi.business.service.MiningOrderService;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class MiningOrderServiceImpl extends BaseServiceImpl<MiningOrderModel, MiningOrderModelDto> implements MiningOrderService {

    @Autowired
    private MiningOrderMapper miningOrderMapper;
    @Autowired
    private MiningConfigMapper miningConfigMapper;
    @Autowired
    private UserWalletMapper userWalletMapper;
    @Autowired
    private UserWalletLogMapper userWalletLogMapper;
    @Autowired
    private CurrencyMapper currencyMapper;
    @Autowired
    private UserLevelMapper userLevelMapper;
    @Autowired
    private MiningBonusPoolConfigMapper miningBonusPoolConfigMapper;
    @Autowired
    private MiningMemberOrderMapper miningMemberOrderMapper;
    @Autowired
    private MiningGradeRewardMapper miningGradeRewardMapper;
    @Autowired
    private UserMapper userMapper;


    @Override
    public BaseMapper<MiningOrderModel, MiningOrderModelDto> getBaseMapper() {
        return this.miningOrderMapper;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ReturnResponse createOrder(long userId, long configId, BigDecimal num) {
        //1.检查入参
        MiningConfigModelDto byId = miningConfigMapper.getById(configId);
        if (byId == null) {
            return ReturnResponse.backFail("未找到对应合约信息");
        }
        if (byId.getCycle() == 1) {
            if (num.compareTo(new BigDecimal(100)) != 0) {
                return ReturnResponse.backFail("该订单仅可投资100U");
            }
        } else {
            if (num.compareTo(new BigDecimal(byId.getInvestMin())) < 0 || num.compareTo(new BigDecimal(byId.getInvestMax())) > 0) {
                return ReturnResponse.backFail("该订单仅可投资" + byId.getInvestMin() + "至" + byId.getInvestMax() + "U");
            }
        }

        //2.检查用户是否存在或未出局订单
        MiningOrderModelDto modelDto = new MiningOrderModelDto();
        modelDto.setUserId(userId);
        modelDto.setIsOut(1);
        modelDto.setMiningId((int) configId);
        List<MiningOrderModelDto> modelDtoDbs = miningOrderMapper.queryList(modelDto);
        if (CollectionUtils.isNotEmpty(modelDtoDbs)) {
            return ReturnResponse.backFail("已存在同等合约订单");
        }

        //3.扣钱  （获取当前阶段对于扣钱比例）
        //查询币种id
        CurrencyModelDto currencyModelDb = currencyMapper.getByName(byId.getCurrency());
        userWalletMapper.modifyWalletUsing(userId, currencyModelDb.getId(), num.negate());
        UserWalletModelDto userWalletModelDto = userWalletMapper.getByUserAndCurrencyId(userId, currencyModelDb.getId());
        // 添加扣钱日志
        UserWalletLogModel logModel = new UserWalletLogModel();
        logModel.setUserId(userId);
        if (currencyModelDb != null) {
            logModel.setCurrencyId(currencyModelDb.getId());
        }
        logModel.setMoney(num.negate());
        logModel.setType(WalletLogTypeEnum.CONTRACT.getCode());
        logModel.setRemark("合约购买");
        logModel.setBalance(userWalletModelDto.getUsing());
        logModel.setSnapshot("可用：" + userWalletModelDto.getUsing() + ",冻结：" + userWalletModelDto.getFreeze());
        userWalletLogMapper.insert(logModel);

        //4.生成订单
        MiningOrderModel orderModel = new MiningOrderModel();
        orderModel.setMiningId((int) configId);
        orderModel.setPayStatus(1);
        orderModel.setPayTime(new Date());
        orderModel.setPrice(num);
        orderModel.setUserId(userId);
        orderModel.setEndCreateTime(new Date());
        orderModel.setIsOut(0);
        //计算到期时间
        if(byId.getCycle()==1){
            orderModel.setExpireTime(getBeforeAfterDate(DateUtil.format(new Date(), "yyyy-MM-dd HH:mm"),1));
        }else {
            orderModel.setExpireTime(getBeforeAfterDate(DateUtil.format(new Date(), "yyyy-MM-dd HH:mm"),7));
        }
        miningOrderMapper.insert(orderModel);

        //5.上级推荐奖励
        List<String> treeInfoList = this.getParentId(userId);
        for (int i = 0; i < treeInfoList.size(); i++) {
            long parentId = Long.parseLong(treeInfoList.get(i));
            MiningOrderModelDto model = new MiningOrderModelDto();
            model.setPayStatus(1);
            model.setUserId(parentId);
            //该级推荐人数据
            List<MiningOrderModelDto> dtos = miningOrderMapper.queryList(model);
            if (dtos != null && dtos.size() > 0) {
                UserLevelModelDto userLevelModelDto = new UserLevelModelDto();
                userLevelModelDto.setParentId(parentId);
                //上级推荐人数量
                List<UserLevelModelDto> userLevelModelDtos = userLevelMapper.queryList(userLevelModelDto);
                for (int a = 0; a < userLevelModelDtos.size(); a++) {
                    MiningOrderModelDto parm = new MiningOrderModelDto();
                    model.setUserId(userLevelModelDtos.get(a).getUserId());
                    model.setPayStatus(1);
                    List<MiningOrderModelDto> orderDtos = miningOrderMapper.queryList(parm);
                    if (CollectionUtils.isEmpty(orderDtos)) {
                        userLevelModelDtos.remove(a);
                    }
                }
                //推荐代数
                int count = 8 + userLevelModelDtos.size();
                //分代奖励 TODO （收益比例查询数据库）
                if (count <= 3) {
                    userWalletMapper.modifyWalletUsing(parentId, currencyModelDb.getId(), num.multiply(new BigDecimal(0.05)).setScale(3, BigDecimal.ROUND_HALF_UP));
                } else if (count <= 6) {
                    userWalletMapper.modifyWalletUsing(parentId, currencyModelDb.getId(), num.multiply(new BigDecimal(0.02)).setScale(3, BigDecimal.ROUND_HALF_UP));

                } else if (count <= 9) {
                    userWalletMapper.modifyWalletUsing(parentId, currencyModelDb.getId(), num.multiply(new BigDecimal(0.05)).setScale(3, BigDecimal.ROUND_HALF_UP));

                } else {
                    userWalletMapper.modifyWalletUsing(parentId, currencyModelDb.getId(), num.multiply(new BigDecimal(0.01)).setScale(3, BigDecimal.ROUND_HALF_UP));

                }

            }
        }
        return ReturnResponse.backSuccess();
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public ReturnResponse consumeCra(long userId, long currencyId, BigDecimal num) {
        // 1.扣减用户CRA币
        userWalletMapper.modifyWalletUsing(userId, currencyId, num.negate());
        // 2.释放锁仓币
        // 计算用户前一天总入金和总出金数据
        List<MiningBonusPoolConfigModelDto> beforeData = miningBonusPoolConfigMapper.queryDayBeforeList(userId, 0);
        //前一天总入金
        BigDecimal beforeTotalEnterMoney = new BigDecimal(0);
        //前一天总出金
        BigDecimal beforeTotalOutMoney = new BigDecimal(0);
        if (CollectionUtils.isNotEmpty(beforeData)) {
            for (MiningBonusPoolConfigModelDto beforePam : beforeData) {
                beforeTotalEnterMoney = beforeTotalEnterMoney.add(beforePam.getEnterMony());
                beforeTotalOutMoney = beforeTotalOutMoney.add(beforePam.getOutMony());
            }
        }
        //前一天总差额（入金-出金）
        BigDecimal beforeDifferenceMoney = beforeTotalEnterMoney.subtract(beforeTotalOutMoney);

        //今天总入金
        BigDecimal todayTotalEnterMoney = new BigDecimal(0);
        //今天总出金
        BigDecimal todayTotalOutMoney = new BigDecimal(0);
        List<MiningBonusPoolConfigModelDto> todayData = miningBonusPoolConfigMapper.queryDayBeforeList(userId, 1);
        if (CollectionUtils.isNotEmpty(todayData)) {
            for (MiningBonusPoolConfigModelDto todayPam : todayData) {
                todayTotalEnterMoney = todayTotalEnterMoney.add(todayPam.getEnterMony());
                todayTotalOutMoney = todayTotalOutMoney.add(todayPam.getOutMony());
            }
        }
        //今天差额（入金-出金）
        BigDecimal todayDifferenceMoney = todayTotalEnterMoney.subtract(todayTotalOutMoney);
        BigDecimal declineDecimal = todayDifferenceMoney.subtract(beforeDifferenceMoney);
        MiningBonusPoolConfigModelDto modelDto = new MiningBonusPoolConfigModelDto();
        modelDto.setUserId((int)userId);
        List<MiningBonusPoolConfigModelDto> modelDotsDb = miningBonusPoolConfigMapper.queryList(modelDto);
        if (CollectionUtils.isNotEmpty(modelDotsDb)) {
            //计算下降0.1,用户奖金池数据进入下一阶段
            if ((declineDecimal.divide(new BigDecimal(100)).abs()).compareTo(new BigDecimal(0.1)) > 0) {

                for (MiningBonusPoolConfigModelDto dto : modelDotsDb) {
                    MiningBonusPoolConfigModelDto model = new MiningBonusPoolConfigModelDto();
                    model.setId(dto.getId());
                    model.setCurrentStage(dto.getCurrentStage() + 1);
                    if (dto.getCurrentStage() == 7) {
                        model.setCurrentStage(7);
                    }
                    model.setUpdateTime(new Date());
                    miningBonusPoolConfigMapper.update(model);
                }
            }

			//上一个阶段未出局的用户本金进入锁仓
			modelDotsDb.forEach(modelDotDb -> {
				//出局（0 未出局，1 出局），锁仓（0 锁仓，1 未锁仓）逻辑
				Integer isOut = modelDotDb.getIsOut();
				//未出局逻辑
				if (isOut.equals(0)) {
					handNotOut(modelDotDb);
				}
				//正常出局逻辑
				else {
					handIsOut(modelDotDb);
				}
			});

        }
        return ReturnResponse.backSuccess();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ReturnResponse createGradeOrder(long userId, long gradeId, BigDecimal num) {
        //1.检查入参
        MiningGradeRewardModelDto byIdDb = miningGradeRewardMapper.getById(gradeId);
        if (byIdDb == null) {
            return ReturnResponse.backFail("未找到相应等级信息");
        }
        if (!byIdDb.getAttribute().equals("V1")) {
            return ReturnResponse.backFail("只能购买V1等级");
        }
        if (num.compareTo(new BigDecimal(2000)) != 0) {
            return ReturnResponse.backFail("V1等级需要2000U");
        }

        // 2.扣钱,添加日志，生成订单
        UserWalletModelDto walletModelDto = new UserWalletModelDto();
        walletModelDto.setUserId(userId);
        walletModelDto.setCurrencyId(1L);
        List<UserWalletModelDto> modelDtos = userWalletMapper.queryList(walletModelDto);
        if (CollectionUtils.isNotEmpty(modelDtos)) {
            if (modelDtos.get(0).getUsing().compareTo(num) < 0) {
                return ReturnResponse.backFail("USDT币不足，请充值");
            }
            CurrencyModelDto currencyModelDb = currencyMapper.getByName("USDT");
            //减U
            userWalletMapper.modifyWalletUsing(userId, currencyModelDb.getId(), num.negate());

            // 添加扣钱日志
            UserWalletModelDto userWalletModelDto = userWalletMapper.getByUserAndCurrencyId(userId, currencyModelDb.getId());
            UserWalletLogModel logModel = new UserWalletLogModel();
            logModel.setUserId(userId);
            logModel.setCurrencyId(currencyModelDb.getId());
            logModel.setMoney(num.negate());
            logModel.setType(WalletLogTypeEnum.GRADE.getCode());
            logModel.setRemark("合约购买");
            logModel.setBalance(userWalletModelDto.getUsing());
            logModel.setSnapshot("可用：" + userWalletModelDto.getUsing() + ",冻结：" + userWalletModelDto.getFreeze());
            userWalletLogMapper.insert(logModel);

            //生成订单
            MiningMemberOrderModel orderModel = new MiningMemberOrderModel();
            orderModel.setGradeId((int) gradeId);
            orderModel.setGradeName("V1");
            orderModel.setPayStatus(1);
            orderModel.setPayTime(new Date());
            orderModel.setPrice(num);
            orderModel.setUserId((int) userId);
            miningMemberOrderMapper.insert(orderModel);

            //更新用户等级
            UserModel userModel = new UserModel();
            userModel.setId(userId);
            userModel.setGrade("V1");
            userMapper.update(userModel);
        }

        // 3.计算等级动态奖励
        //查询父级树
        List<String> parentIds = this.getParentId(userId);
        if (CollectionUtils.isNotEmpty(parentIds)) {
            for (String parentId : parentIds) {
                //查看父账号是否购买V1
                MiningMemberOrderModelDto memberOrderModelDto = new MiningMemberOrderModelDto();
                memberOrderModelDto.setUserId(Integer.valueOf(parentId));
                memberOrderModelDto.setPayStatus(1);
                List<MiningMemberOrderModelDto> orderModelDtos = miningMemberOrderMapper.queryList(memberOrderModelDto);
                if (CollectionUtils.isEmpty(orderModelDtos)) {
                    parentIds.remove(parentId);
                }
            }
        }
        //判断伞下等级(当前parentIds均已购买v1等级)
        parentIds.forEach(parentId -> {
            List<String> parentChildIds = this.getParentId(Long.valueOf(parentId));
            int v1 = 0;
            int v2 = 0;
            int v3 = 0;
            int v4 = 0;
            int v5 = 0;
            int v6 = 0;
            //查询当前用户等级
            for (String parentChildId : parentChildIds) {
                UserModelDto userModelDto = userMapper.getById(Long.valueOf(parentChildId));
                if (userModelDto.getGrade().equals("V1")) {
                    v1++;
                } else if (userModelDto.getGrade().equals("V2")) {
                    v2++;
                } else if (userModelDto.getGrade().equals("V3")) {
                    v3++;
                } else if (userModelDto.getGrade().equals("V4")) {
                    v4++;
                } else if (userModelDto.getGrade().equals("V5")) {
                    v5++;
                } else {
                    v6++;
                }
            }
            //升级用户等级
            UserModel userModel = new UserModel();
            userModel.setId(Long.valueOf(parentId));
            if (v1 >= 3) {
                userModel.setGrade("V2");
            }
            if (v2 >= 3) {
                userModel.setGrade("V3");
            }
            if (v3 >= 3) {
                userModel.setGrade("V4");
            }
            if (v4 >= 3) {
                userModel.setGrade("V5");
            }
            if (v5 >= 3) {
                userModel.setGrade("V6");
            }
            if (v6 >= 3) {
                userModel.setGrade("VMax");
            }
            userMapper.update(userModel);
        });
        return ReturnResponse.backSuccess();
    }

    /**
     * 获取上级列表
     * @param userId
     * @return
     */
    private List<String> getParentId(long userId) {
        UserLevelModel level = userLevelMapper.getByUserId(userId);
        String userTreeInfo = level.getTreeInfo();
        List<String> treeInfoList = Arrays.asList(userTreeInfo.substring(1, userTreeInfo.length() - 1).split(","));
        treeInfoList = new ArrayList<>(treeInfoList);
        //去除自己
        for (int i = 0; i < treeInfoList.size(); i++) {
            if (treeInfoList.get(i).equals(String.valueOf(userId))) {
                treeInfoList.remove(i);
            }
        }
        return treeInfoList;
    }

    /**
	 * 处理正常出局逻辑，满周期加收益
	 * @param param
	 */
	private void handIsOut(MiningBonusPoolConfigModelDto param) {
		MiningBonusPoolConfigModelDto byId = miningBonusPoolConfigMapper.getById(param.getId());
		//判断周期
		if(byId.getCycle().equals("1")){
			//计算当前周期
			String dayStr = null;
			try {
				dayStr = TimeDiff(DateUtil.format(byId.getCreateTime(), "yyyy-MM-dd HH:mm"),DateUtil.format(new Date(), "yyyy-MM-dd HH:mm"));
			} catch (Exception e) {
				log.info("日期解析异常");
			}
			if (dayStr.equals("1")) {
				//增加0.01收益
				BigDecimal interest = byId.getPrincipal().multiply(new BigDecimal(0.01)).setScale(3, BigDecimal.ROUND_HALF_UP);
				MiningBonusPoolConfigModel changeModel = new MiningBonusPoolConfigModel();
				changeModel.setId(byId.getId());
				changeModel.setInterest(interest);
				changeModel.setTotalGold(byId.getPrincipal().add(interest));
				miningBonusPoolConfigMapper.update(changeModel);
			}
		}else {
			//计算当前周期
			String dayStr = null;
			try {
				dayStr = TimeDiff(DateUtil.format(byId.getCreateTime(), "yyyy-MM-dd HH:mm"),DateUtil.format(new Date(), "yyyy-MM-dd HH:mm"));
			} catch (Exception e) {
				log.info("日期解析异常");
			}
			if (dayStr.equals("7")) {
				//增加0.1收益
				BigDecimal interest = byId.getPrincipal().multiply(new BigDecimal(0.1)).setScale(3, BigDecimal.ROUND_HALF_UP);
				MiningBonusPoolConfigModel changeModel = new MiningBonusPoolConfigModel();
				changeModel.setId(byId.getId());
				changeModel.setInterest(interest);
				changeModel.setTotalGold(byId.getPrincipal().add(interest));
				miningBonusPoolConfigMapper.update(changeModel);
			}
		}
	}

	/**
	 * 处理未出局逻辑，释放3%锁仓币
	 * @param param
	 */
	private void handNotOut(MiningBonusPoolConfigModelDto param) {
		MiningBonusPoolConfigModelDto byId = miningBonusPoolConfigMapper.getById(param.getId());
		MiningBonusPoolConfigModel changeModel = new MiningBonusPoolConfigModel();
		changeModel.setId(byId.getId());
		changeModel.setUpdateTime(new Date());
		changeModel.setCurrentStage(byId.getCurrentStage() + 1);
		if(param.getCurrentStage() == 7){
			changeModel.setCurrentStage(7);
		}
		changeModel.setIsLock(0);
		//释放3%锁仓币
		BigDecimal multiply = byId.getPrincipal().multiply(new BigDecimal(0.03)).setScale(3, BigDecimal.ROUND_HALF_UP);
		changeModel.setPrincipal(byId.getPrincipal().subtract(multiply));
		miningBonusPoolConfigMapper.update(changeModel);
	}

	/**
	 * 计算时间段天数
	 * @param pBeginTime 开始时间
	 * @param pEndTime 结束时间
	 * @return
	 * @throws Exception
	 */
	public static String TimeDiff(String pBeginTime, String pEndTime) throws Exception {
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm");
		Long beginL = format.parse(pBeginTime).getTime();
		Long endL = format.parse(pEndTime).getTime();
		Long day = (endL - beginL)/86400000;
		Long hour = ((endL - beginL)%86400000)/3600000;
		Long min = ((endL - beginL)%86400000%3600000)/60000;
		return String.valueOf(day);
	}


    /**
     *
     * @param datestr 日期字符串
     * @param day  oldlace，为正数表示之后，为负数表示之前
     * @return 指定日期字符串n天之前或者之后的日期
     */
    public static Date getBeforeAfterDate(String datestr, int day) {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        java.sql.Date oldDate = null;
        try {
            df.setLenient(false);
            oldDate = new java.sql.Date(df.parse(datestr).getTime());
        } catch (Exception e) {
            throw new RuntimeException("日期转换错误");
        }
        Calendar cal = new GregorianCalendar();
        cal.setTime(oldDate);

        int Year = cal.get(Calendar.YEAR);
        int Month = cal.get(Calendar.MONTH);
        int Day = cal.get(Calendar.DAY_OF_MONTH);

        int NewDay = Day + day;

        cal.set(Calendar.YEAR, Year);
        cal.set(Calendar.MONTH, Month);
        cal.set(Calendar.DAY_OF_MONTH, NewDay);

        return new java.sql.Date(cal.getTimeInMillis());
    }
}
